/* 
 * CVSReader.java created at: 2006-6-4 11:33:54 by elvis
 * $Id: CSVReader.java,v 1.1 2006/06/08 02:49:57 fenghm Exp $ 
 */

package net.bingosoft.common.util;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Vector;

/**
 *
 */
public class CSVReader {

    protected String[] columnNames;

    protected String[] columns;

    protected String buf = null;

    protected char separator = ',';

    protected boolean suppressHeaders = true;

    protected String tableName;

    protected String fileName;

    protected String charset = "GBK";

    private BufferedReader input;

    public CSVReader(InputStream cvsIn) {
        init(cvsIn);
    }

    public CSVReader(String csvFileName) {

        FileInputStream in = null;
        try {
            in = new FileInputStream(csvFileName);
            init(in);
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
    
    /**
     * 通知reader此csv文件第一行为header
     */
    public void hasHeader(){
        this.suppressHeaders = false;
    }

    private void init(InputStream cvsIn) {
        try {
            if (charset != null) {
                input = new BufferedReader(new InputStreamReader(cvsIn, charset));
            } else {
                input = new BufferedReader(new InputStreamReader(cvsIn));
            }

            // input = new BufferedReader(new FileReader(fileName));
            if (this.suppressHeaders) {
                // No column names available. Read first data line and determine number of colums.
                buf = input.readLine();
                String[] data = parseCsvLine(buf);
                columnNames = new String[data.length];
                for (int i = 0; i < data.length; i++) {
                    columnNames[i] = "COLUMN" + String.valueOf(i + 1);
                }
                data = null;
                // throw away.
            } else {
                String headerLine = input.readLine();
                columnNames = parseCsvLine(headerLine);
            }
        }catch(IOException e){
            throw new RuntimeException(e);
        } finally {
            try {
                cvsIn.close();
            } catch (IOException e) {
                ;
            }
        }
    }

    /**
     * Description of the Method
     * @return     Description of the Returned Value
     * @exception  RuntimeException  Description of Exception
     * @since
     */
    public boolean next() {
        columns = new String[columnNames.length];
        String dataLine = null;
        try {
            if (suppressHeaders && (buf != null)) {
                // The buffer is not empty yet, so use this first.
                dataLine = buf;
                buf = null;
            } else {
                // read new line of data from input.
                dataLine = input.readLine();
            }
            if (dataLine == null) {
                input.close();
                return false;
            }
        } catch (IOException e) {
            if(e.getMessage() != null && e.getMessage().indexOf("Bad file descriptor") == -1){
                throw new RuntimeException(e);    
            }else{
                try {
                    input.close();
                } catch (IOException e1) {
                    ;
                }
                return false;    
            }
        }
        
        columns = parseCsvLine(dataLine);
        
        return true;
    }
    
    /**
     * @return
     */
    public int getColumnCount(){
        if(null != columns){
            return columns.length;
        }
        return 0;
    }
    
    /**
     * @return
     */
    public String[] getColumns(){
        return columns;
    }
    
    /**
     * 从1开始
     * @param index
     * @return
     */
    public String getColumn(int index){
        if(null != columns){
            return columns[index-1];
        }
        return null;
    }

    // This code updated with code by Stuart Mottram to handle line breaks in fields
    // see bug #492063
    protected String[] parseCsvLine(String line) {
        Vector values = new Vector();
        boolean inQuotedString = false;
        String value = "";
        String orgLine = line;
        int currentPos = 0;
        int fullLine = 0;

        while (fullLine == 0) {
            currentPos = 0;
            line += separator;
            while (currentPos < line.length()) {
                char currentChar = line.charAt(currentPos);
                if (value.length() == 0 && currentChar == '"' && !inQuotedString) {
                    currentPos++;
                    inQuotedString = true;
                    continue;
                }
                if (currentChar == '"') {
                    char nextChar = line.charAt(currentPos + 1);
                    if (nextChar == '"') {
                        value += currentChar;
                        currentPos++;
                    } else {
                        if (!inQuotedString) {
                            throw new RuntimeException("Unexpected '\"' in position " + currentPos + ". Line="
                                    + orgLine);
                        }
                        if (inQuotedString && nextChar != separator) {
                            throw new RuntimeException("Expecting " + separator + " in position " + (currentPos + 1)
                                    + ". Line=" + orgLine);
                        }
                        values.add(value);
                        value = "";
                        inQuotedString = false;
                        currentPos++;
                    }
                } else {
                    if (currentChar == separator) {
                        if (inQuotedString) {
                            value += currentChar;
                        } else {
                            values.add(value);
                            value = "";
                        }
                    } else {
                        value += currentChar;
                    }
                }
                currentPos++;
            }
            if (inQuotedString) {
                // Remove extra , added at start
                value = value.substring(0, value.length() - 1);
                try {
                    line = input.readLine();
                } catch (IOException e) {
                    throw new RuntimeException(e.toString());
                }
            } else {
                fullLine = 1;
            }

        }
        String[] retVal = new String[values.size()];
        values.copyInto(retVal);
        return retVal;
    }

}
